package org.gikolet.ch2.android.widget;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.gikolet.ch2.data.Res;

import android.graphics.Color;
import android.graphics.Typeface;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.text.style.URLSpan;
import android.view.View;

public class ResSpannableParser {
	// リンクの抽出のみ
	private static final Pattern INNER_LINK_PTN = Pattern
			.compile("(>>|＞＞|>|＞|≫)[0-9０-９]+(-([0-9０-９]+)?)?(,[0-9０-９]+(-([0-9０-９]+)?)?)*");

	private static final Pattern INNER_LINK_PTN2 = Pattern
			.compile("[0０]*([0-9０-９]+)(-([0０]*([0-9０-９]+))?)?");

	private static final Pattern URL_PTN = Pattern
			.compile("(http://|https://){1}[\\w\\.\\-/:]+");

	private static final RelativeSizeSpan BIG_SPAN = new RelativeSizeSpan(1.25f);

	private static final StyleSpan BOLD_STYLE_SPAN = new StyleSpan(
			Typeface.BOLD);

	private static final ForegroundColorSpan NAME_COLOR_SPAN = new ForegroundColorSpan(
			Color.rgb(0x00, 0x80, 0x00));

	private OnResClickListener onResClickListener;

	public void setOnResClickListener(OnResClickListener l) {
		this.onResClickListener = l;
	}

	public Spannable toSpannable(int no, Res res) {

		SpannableStringBuilder sb = new SpannableStringBuilder();

		appendSpannable(sb, no, res);

		return sb;
	}

	public void appendSpannable(SpannableStringBuilder sb, int no, Res res) {
		String noStr = String.valueOf(no);
		String name = res.getName();
		String mail = res.getMail();
		String date = res.getDateString();
		String body = res.getBody();

		append(sb, noStr, BOLD_STYLE_SPAN, BIG_SPAN, new ResNoClickableSpan(no));

		if (!"".intern().equals(name)) {
			append(sb, name, NAME_COLOR_SPAN);
		}
		if (!"".intern().equals(mail)) {
			append(sb, "[" + mail + "]");
		}
		if (!"".intern().equals(date)) {
			append(sb, date);
		}
		append(sb, "\n");
		if (!"".intern().equals(body)) {
			append(sb, body);
		}

		// Linkify.addLinks(sb, INNER_LINK_PTN, "test");
		addSpan(sb, INNER_LINK_PTN);
		addSpan(sb, URL_PTN);
	}

	private static void append(SpannableStringBuilder sb, String str,
			Object... whats) {

		int start = sb.length();
		int end = start + str.length();

		sb.append(str);

		for (Object what : whats) {
			sb.setSpan(what, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
	}

	private boolean addSpan(Spannable s, Pattern p) {
		boolean hasMatches = false;
		// String prefix = (scheme == null) ? "" : scheme.toLowerCase();
		Matcher m = p.matcher(s);

		while (m.find()) {
			int start = m.start();
			int end = m.end();

			applySpan(p, m, start, end, s);
			hasMatches = true;
		}

		return hasMatches;
	}

	private void applySpan(Pattern p, Matcher m, int start, int end,
			Spannable text) {

		Object span;

		if (p == INNER_LINK_PTN) {
			Matcher m2 = INNER_LINK_PTN2.matcher(m.group());

			boolean first = true;

			while (m2.find()) {
				String startStr = m2.group(1);
				String endStr = m2.group(4);

				int startResNo = Integer.parseInt(startStr);
				int endResNo = -1;

				if (endStr != null) {
					endResNo = Integer.parseInt(endStr);
				}

				span = new ResAnchorClickableSpan(startResNo, endResNo);

				text.setSpan(span, start + (first ? 0 : m2.start()), start
						+ m2.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

				first = false;
			}

		} else if (p == URL_PTN) {

			span = new URLSpan(m.group(0));

			text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
	}

	private void onResNoClick(int resNo) {
		OnResClickListener l = this.onResClickListener;
		if (l != null) {
			l.onResNoClick(resNo);
		}
	}

	private void onResAnchorClick(int startResNo, int endResNo) {
		OnResClickListener l = this.onResClickListener;
		if (l != null) {
			l.onResAnchorClick(startResNo, endResNo);
		}
	}

	class ResNoClickableSpan extends ClickableSpan {

		private int resNo;

		public ResNoClickableSpan(int resNo) {
			this.resNo = resNo;
		}

		@Override
		public void onClick(View view) {
			onResNoClick(resNo);
		}
	}

	class ResAnchorClickableSpan extends ClickableSpan implements ResAnchorSpan {

		private int startResNo;
		private int endResNo;

		public ResAnchorClickableSpan(int startResNo, int endResNo) {
			this.startResNo = startResNo;
			this.endResNo = endResNo;
		}

		@Override
		public void onClick(View view) {
			onResAnchorClick(startResNo, endResNo);
		}

		public int getStartResNo() {
			return this.startResNo;
		}

		public int getEndResNo() {
			return this.endResNo;
		}
	}
}
